'use strict';

/* global describe, it */

var chai = require('chai');
var assert = chai.assert;
var base32 = require('base32.js');
var speakeasy = require('..');

// These tests use the information from RFC 4226's Appendix D: Test Values.
// http://tools.ietf.org/html/rfc4226#appendix-D

describe('Generator tests', function () {
  it('Normal generation with defaults', function () {
    var secret = speakeasy.generateSecret();
    assert.equal(secret.ascii.length, 32, 'Should return the correct length');

    // check returned fields
    assert.isDefined(secret.otpauth_url, 'otpauth:// URL should be returned');
    assert.isUndefined(secret.qr_code_ascii, 'QR Code ASCII should not be returned');
    assert.isUndefined(secret.qr_code_hex, 'QR Code Hex should not be returned');
    assert.isUndefined(secret.qr_code_base32, 'QR Code Base 32 should not be returned');
    assert.isUndefined(secret.google_auth_qr, 'Google Auth QR should not be returned');

    // check encodings
    assert.equal(Buffer(secret.hex, 'hex').toString('ascii'), secret.ascii, 'Should have encoded correct hex string');
    assert.equal(base32.decode(secret.base32).toString('ascii'), secret.ascii, 'Should have encoded correct base32 string');
  });

  it('Generation with custom key length', function () {
    var secret = speakeasy.generateSecret({length: 50});
    assert.equal(secret.ascii.length, 50, 'Should return the correct length');
  });

  it('Generation with symbols disabled', function () {
    var secret = speakeasy.generateSecret({symbols: false});
    assert.ok(/^[a-z0-9]+$/i.test(secret.ascii), 'Should return an alphanumeric key');
  });

  it('Generation with QR URL output enabled', function () {
    var secret = speakeasy.generateSecret({qr_codes: true});
    assert.isDefined(secret.qr_code_ascii, 'QR Code ASCII should be returned');
    assert.isDefined(secret.qr_code_hex, 'QR Code Hex should be returned');
    assert.isDefined(secret.qr_code_base32, 'QR Code Base 32 should be returned');
  });

  it('Generation with otpath:// URL output disabled', function () {
    var secret = speakeasy.generateSecret({otpauth_url: false});
    assert.isUndefined(secret.otpauth_url, 'Google Auth URL should not be returned');
  });

  it('Generation with Google Auth QR URL output enabled', function () {
    var secret = speakeasy.generateSecret({google_auth_qr: true});
    assert.isDefined(secret.google_auth_qr, 'Google Auth QR should be returned');
  });

  it('Testing generateSecretASCII with defaults', function () {
    var secret = speakeasy.generateSecretASCII();
    assert.equal(secret.length, 32, 'Should return the correct length');
    assert.ok(/^[a-z0-9]+$/i.test(secret.ascii), 'Should return an alphanumeric key');
  });

  it('Testing generateSecretASCII with custom length', function () {
    var secret = speakeasy.generateSecretASCII(20);
    assert.equal(secret.length, 20, 'Should return the correct length');
    assert.ok(/^[a-z0-9]+$/i.test(secret.ascii), 'Should return an alphanumeric key');
  });

  it('Testing backward compatibility (deprecated function) generate_key', function () {
    var secret = speakeasy.generate_key();
    assert.ok(secret, 'Should return a secret');
    assert.equal(secret.ascii.length, 32, 'Should return default secret length');
  });

  it('Testing backward compatibility (deprecated function) generate_key_ascii', function () {
    var secret = speakeasy.generate_key_ascii(20);
    assert.ok(secret, 'Should return a secret');
    assert.equal(secret.length, 20, 'Should return the correct length');
  });

  it('Testing otp URL generated by generateSecret', function () {
    var answer = speakeasy.generateSecret({
      name: 'Example:alice@google.com'
    });

    var secret = new Buffer(answer.ascii, 'ascii');
    if (Buffer.isBuffer(secret)) secret = base32.encode(secret);

    var expect = 'otpauth://totp/Example%3Aalice%40google.com?secret=' + secret + '&algorithm=SHA1&digits=6&period=30';
    assert.deepEqual(
      answer.otpauth_url,
      expect
    );
  });

  it('Testing otp URL generated by generate_key', function () {
    var answer = speakeasy.generate_key({
      name: 'Example:alice@google.com'
    });

    var secret = new Buffer(answer.ascii, 'ascii');
    if (Buffer.isBuffer(secret)) secret = base32.encode(secret);

    var expect = 'otpauth://totp/Example%3Aalice%40google.com?secret=' + secret + '&algorithm=SHA1&digits=6&period=30';
    assert.deepEqual(
      answer.otpauth_url,
      expect
    );
  });

  it('Testing google_auth_qr generated by generate_key', function () {
    var answer = speakeasy.generate_key({
      name: 'Example:alice@google.com',
      google_auth_qr: true
    });

    var secret = new Buffer(answer.base32, 'ascii');
    if (Buffer.isBuffer(secret)) secret = base32.encode(secret);

    var google_chart_url = 'https://chart.googleapis.com/chart?chs=166x166&chld=L|0&cht=qr&chl=';    
    var encodedOtpUrl = encodeURIComponent('otpauth://totp/Example%3Aalice%40google.com?secret=' + secret + '&algorithm=SHA1&digits=6&period=30');
    var expect = google_chart_url + encodedOtpUrl;
    assert.deepEqual(
      answer.google_auth_qr,
      expect
    );
  });

  it('Testing otp URL generated with issuer by generateSecret', function () {
    var answer = speakeasy.generateSecret({
      name: 'Example:alice@google.com',
      issuer: 'issuer name'
    });

    var secret = new Buffer(answer.ascii, 'ascii');
    if (Buffer.isBuffer(secret)) secret = base32.encode(secret);

    var expect = 'otpauth://totp/Example%3Aalice%40google.com?secret=' + secret + '&issuer=issuer%20name&algorithm=SHA1&digits=6&period=30';
    assert.deepEqual(
      answer.otpauth_url,
      expect
    );
  });
});
